package xlog

import (
	"bytes"
	"runtime"
	"strings"
	"time"
)

type Entry struct {
	logger *logger

	// 基础字段
	Level Level // 每次调用时的日志级别
	Time  time.Time
	File  string
	Line  int
	Func  string

	// 输出为 json 时临时存放数据
	Map map[string]interface{}

	// 日志格式化输出的格式串和参数
	Format string
	Args   []interface{}

	// 输出缓冲
	Buffer *bytes.Buffer
}

func entry(logger *logger) *Entry {
	return &Entry{logger: logger, Buffer: new(bytes.Buffer), Map: make(map[string]interface{}, 5)}
}

func (e *Entry) write(level Level, format string, args ...interface{}) {
	// 本次写日志级别比预定义的日志级别低，直接返回
	if e.logger.opt.level > level {
		return
	}

	e.Time = time.Now()
	e.Level = level
	e.Format = format
	e.Args = args
	// 拿到调用栈信息
	if !e.logger.opt.disableCaller {
		// 0 是当前函数，1 是 logger 中的函数，2 是业务代码中调用日志方法的地方所在的函数
		if pc, file, line, ok := runtime.Caller(2); !ok {
			e.File = "???"
			e.Func = "???"
		} else {
			e.File, e.Line, e.Func = file, line, runtime.FuncForPC(pc).Name()
			e.Func = e.Func[strings.LastIndex(e.Func, "/")+1:]
		}
	}
	// 日志内容格式化
	e.format()
	// 日志输出
	e.flush()
	// 对象重置
	e.release()
}

func (e *Entry) format() {
	_ = e.logger.opt.formatter.Format(e)
}

func (e *Entry) flush() {
	e.logger.mu.Lock()
	_, _ = e.logger.opt.output.Write(e.Buffer.Bytes())
	e.logger.mu.Unlock()
}

func (e *Entry) release() {
	e.Args, e.Line, e.File, e.Format, e.Func = nil, 0, "", "", ""
	e.Buffer.Reset()
	e.logger.entryPool.Put(e)
}
